﻿using NUnit.Framework;
using Sasa.QualityTools.CodeAnalysis.Cli;
using System;
using System.IO;
using Sasa.QualityTools.CodeAnalysis.Core;
using System.Linq;
using Sasa.QualityTools.CodeAnalysis.Core.Models;

namespace Sasa.QualityTools.CodeAnalysis.Cli.Tests.Unit
{
    [TestFixture]
    public class ProgramTest
    {
        private static readonly string ResourceDir = Path.Combine(Environment.CurrentDirectory, "Resources", "Program");

        private static readonly string RuleSetDir = Path.Combine(Environment.GetEnvironmentVariable("PROGRAMFILES"), "Microsoft Visual Studio 10.0", "Team Tools", "Static Analysis Tools", "Rule Sets");

        private Program testee;


        [SetUp]
        public void SetUp()
        {
            testee = new Program();
        }

        [Test]
        public void BuildUpSolutionShouldThrowExceptionWhenSolutionDirIsNotSpecified()
        {
            Assert.Throws<ExecutionException>(() => Program.BuildUpSolution(new string[] { }));
        }

        [Test]
        public void BuildUpSolutionShouldCreateSolutionCorrectly()
        {
            var args = new string[] { @"/s:C:\tmp" };
            var solution = Program.BuildUpSolution(args);

            Assert.AreEqual(Path.Combine(@"C:\tmp", Constants.CodeAnalysisConfigurationDirName), solution.ConfigurationDir);
            Assert.AreEqual(Path.Combine(@"C:\tmp", Constants.CodeAnalysisConfigurationDirName, Constants.CodeAnalysisConfigurationFileName), solution.ConfigurationPath);
            Assert.AreEqual(Path.Combine(@"C:\tmp", Constants.CodeAnalysisConfigurationDirName, Constants.FxCopDictionaryFileName), solution.FxCopDictionaryPath);
        }

        [Test]
        public void BuildUpProjectShouldThrowExceptionWhenProjectDirIsNotSpecified()
        {
            Assert.Throws<ExecutionException>(() => Program.BuildUpProject(new string[] { "/f:test.dll" }));
        }

        [Test]
        public void BuildUpProjectShouldThrowExceptionWhenAssemblyPathIsNotSpecified()
        {
            Assert.Throws<ExecutionException>(() => Program.BuildUpProject(new string[] { "/p:project" }));
        }

        [Test]
        public void BuildUpProjectShouldCreateProjectCorrectlyWhenDependenciesAreNotSpecified()
        {
            var args = new string[] { @"/f:C:\asm\test.exe", @"/p:C:\tmp" };
            var project = Program.BuildUpProject(args);

            Assert.AreEqual(Path.Combine(@"C:\tmp", Constants.CodeAnalysisConfigurationDirName, Constants.CodeAnalysisConfigurationFileName), project.ConfigurationPath);
            Assert.AreEqual(@"C:\asm", project.TargetDir);
            Assert.AreEqual(@"C:\asm\test.exe", project.AssemblyPath);
            Assert.AreEqual(0, project.DependencyDirectories.Count());
        }

        [Test]
        public void BuildUpProjectShouldCreateProjectCorrectlyWhenDependenciesAreSpecified()
        {
            var args = new string[] { @"/f:C:\asm\test.exe", @"/p:C:\tmp", "/d:A", "/d:B", "/d:C" };
            var project = Program.BuildUpProject(args);

            Assert.AreEqual(Path.Combine(@"C:\tmp", Constants.CodeAnalysisConfigurationDirName, Constants.CodeAnalysisConfigurationFileName), project.ConfigurationPath);
            Assert.AreEqual(@"C:\asm", project.TargetDir);
            Assert.AreEqual(@"C:\asm\test.exe", project.AssemblyPath);
            CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, project.DependencyDirectories.ToList());
        }

        [Test]
        public void ExecuteShouldPerformCodeAnalysisCorrectly()
        {
            var args = new string[] {
                String.Format("/f:{0}", Path.Combine(ResourceDir, "Success", "TestTarget.dll")),
                String.Format("/s:{0}", Path.Combine(ResourceDir, "Solution")),
                String.Format("/p:{0}", Path.Combine(ResourceDir, "Project"))
            };

            testee.Execute(args);

            var report = new FxCopReport();
            report.Load(Path.Combine(ResourceDir, "Success", Constants.CodeAnalysisReportFileName));
            Assert.AreEqual(19, report.Problems.Count);
            Assert.AreEqual(13, report.Rules.Count);
        }

        [Test]
        public void ExecuteShouldThrowExceptionWhenFxCopFailed()
        {
            var args = new string[] {
                String.Format("/f:{0}", Path.Combine(ResourceDir, "Fail", "TestTarget.AnalysisError.dll")),
                String.Format("/s:{0}", Path.Combine(ResourceDir, "Solution")),
                String.Format("/p:{0}", Path.Combine(ResourceDir, "Project"))
            };

            Assert.Throws<ExecutionException>(() => testee.Execute(args));
        }
    }
}
